﻿/***************************************************
//  Copyright (c) Premium Tax Free 2011
***************************************************/

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Collections;

namespace PremierTaxFree.PTFLib.Extensions
{
    public static class StringEx
    {
        public static void ReplaceLast(this StringBuilder b, char oldChar, char newChar)
        {
            for (int i = b.Length - 1; i >= 0; i--)
            {
                if (b[i] == oldChar)
                {
                    b.Replace(oldChar, newChar, i, 1);
                    return;
                }
            }
        }

        #region TripleDESCryptography

        /// <summary>
        /// 
        /// </summary>
        /// <param name="text"></param>
        /// <param name="passphrase"></param>
        /// <returns></returns>
        /// <example>
        /// string Msg = "This world is round, not flat, don't believe them!";
        /// string Password = "secret";
        /// string EncryptedString = Msg.Encrypt(Password);
        /// string DecryptedString = EncryptedString.Decrypt(Password);
        /// </example>
        public static string Encrypt(this string text, string passphrase)
        {
            byte[] Results;
            UTF8Encoding UTF8 = new UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the encoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToEncrypt = UTF8.GetBytes(text);

            // Step 5. Attempt to encrypt the string
            try
            {
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the encrypted string as a base64 encoded string
            return Convert.ToBase64String(Results);
        }

        public static string Decrypt(this string text, string passphrase)
        {
            byte[] Results;
            UTF8Encoding UTF8 = new UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the decoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToDecrypt = Convert.FromBase64String(text);

            // Step 5. Attempt to decrypt the string
            try
            {
                ICryptoTransform decryptor = TDESAlgorithm.CreateDecryptor();
                Results = decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the decrypted string in UTF8 format
            return UTF8.GetString( Results );
        }

        #endregion

        #region DESCryptography

        // Fields
        private const string EMPTY = "<%@EMPTY@%>";

        public static string Encrypt(this string originalString, byte[] key)
        {
            if (string.IsNullOrEmpty(originalString))
            {
                originalString = EMPTY;
            }
            if (key.Length < 8)
            {
                throw new ArgumentException("Password key length should be nore than 8");
            }
            byte[] destinationArray = new byte[8];
            Array.Copy(key, destinationArray, 8);
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(destinationArray, destinationArray), CryptoStreamMode.Write);
            StreamWriter writer = new StreamWriter(stream2);
            writer.Write(originalString);
            writer.Flush();
            stream2.FlushFinalBlock();
            writer.Flush();
            return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length);
        }

        // Methods
        public static string Decrypt(this string cryptedString, byte[] key)
        {
            if (string.IsNullOrEmpty(cryptedString))
            {
                throw new ArgumentNullException("The string which needs to be decrypted can not be null.");
            }
            if (key.Length < 8)
            {
                throw new ArgumentException("Password key length should be nore than 8");
            }
            byte[] destinationArray = new byte[8];
            Array.Copy(key, destinationArray, 8);
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
            MemoryStream stream = new MemoryStream(Convert.FromBase64String(cryptedString));
            CryptoStream stream2 = new CryptoStream(stream, provider.CreateDecryptor(destinationArray, destinationArray), CryptoStreamMode.Read);
            string str = new StreamReader(stream2).ReadToEnd();
            if (string.CompareOrdinal(str, EMPTY) == 0)
            {
                return string.Empty;
            }
            return str;
        }

        #endregion
    }
}
